package com.company.hive.monitor;

import org.apache.hadoop.conf.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

/**
 * 告警规则管理器
 * 负责判断是否需要发送告警，以及管理白名单、黑名单等规则
 */
public class AlertRuleManager {
    
    private static final Logger LOG = LoggerFactory.getLogger(AlertRuleManager.class);
    
    // 配置键
    private static final String DROP_TABLE_WHITELIST_KEY = "hive.metastore.monitor.drop.table.whitelist";
    private static final String DROP_TABLE_BLACKLIST_KEY = "hive.metastore.monitor.drop.table.blacklist";
    private static final String DROP_DB_WHITELIST_KEY = "hive.metastore.monitor.drop.database.whitelist";
    private static final String TABLE_OVERWRITE_WINDOW_KEY = "hive.metastore.monitor.overwrite.time.window";
    
    // 白名单和黑名单
    private final List<Pattern> tableWhitelistPatterns;
    private final List<Pattern> tableBlacklistPatterns;
    private final List<Pattern> dbWhitelistPatterns;
    
    // 表覆盖检测：记录最近删除的表
    private final Map<String, Long> recentDeletes;
    private final long overwriteTimeWindow;  // 时间窗口（毫秒）
    
    public AlertRuleManager(Configuration config) {
        // 加载删表白名单
        this.tableWhitelistPatterns = loadPatterns(
            config.get(DROP_TABLE_WHITELIST_KEY, "tmp_*,test_*")
        );
        
        // 加载删表黑名单
        this.tableBlacklistPatterns = loadPatterns(
            config.get(DROP_TABLE_BLACKLIST_KEY, "")
        );
        
        // 加载删库白名单
        this.dbWhitelistPatterns = loadPatterns(
            config.get(DROP_DB_WHITELIST_KEY, "test_*,tmp_*")
        );
        
        // 表覆盖检测时间窗口（默认5分钟）
        this.overwriteTimeWindow = config.getLong(TABLE_OVERWRITE_WINDOW_KEY, 300000L);
        
        // 初始化最近删除记录
        this.recentDeletes = new ConcurrentHashMap<>();
        
        // 启动清理线程
        startCleanupThread();
        
        LOG.info("告警规则管理器初始化完成");
        LOG.info("删表白名单: {}", config.get(DROP_TABLE_WHITELIST_KEY, "tmp_*,test_*"));
        LOG.info("删库白名单: {}", config.get(DROP_DB_WHITELIST_KEY, "test_*,tmp_*"));
        LOG.info("表覆盖检测时间窗口: {}ms", overwriteTimeWindow);
    }
    
    /**
     * 判断删表操作是否需要告警
     */
    public boolean shouldAlertForDropTable(String dbName, String tableName) {
        String fullName = dbName + "." + tableName;
        
        // 记录删除操作
        recordTableDeletion(fullName);
        
        // 检查黑名单（黑名单优先级最高）
        if (matchesAny(fullName, tableBlacklistPatterns)) {
            LOG.info("表 {} 在黑名单中，需要告警", fullName);
            return true;
        }
        
        // 检查白名单
        if (matchesAny(fullName, tableWhitelistPatterns)) {
            LOG.debug("表 {} 在白名单中，跳过告警", fullName);
            return false;
        }
        
        // 默认告警
        return true;
    }
    
    /**
     * 判断删库操作是否需要告警
     */
    public boolean shouldAlertForDropDatabase(String dbName) {
        // 检查白名单
        if (matchesAny(dbName, dbWhitelistPatterns)) {
            LOG.debug("数据库 {} 在白名单中，跳过告警", dbName);
            return false;
        }
        
        // 默认告警
        return true;
    }
    
    /**
     * 判断表是否最近被删除过（用于表覆盖检测）
     */
    public boolean isRecentlyDeleted(String dbName, String tableName) {
        String fullName = dbName + "." + tableName;
        
        Long deleteTime = recentDeletes.get(fullName);
        if (deleteTime == null) {
            return false;
        }
        
        long now = System.currentTimeMillis();
        return (now - deleteTime) <= overwriteTimeWindow;
    }
    
    /**
     * 记录表删除操作
     */
    private void recordTableDeletion(String fullTableName) {
        recentDeletes.put(fullTableName, System.currentTimeMillis());
    }
    
    /**
     * 加载模式列表
     */
    private List<Pattern> loadPatterns(String patternStr) {
        if (patternStr == null || patternStr.trim().isEmpty()) {
            return Collections.emptyList();
        }
        
        List<Pattern> patterns = new ArrayList<>();
        String[] parts = patternStr.split(",");
        
        for (String part : parts) {
            String trimmed = part.trim();
            if (!trimmed.isEmpty()) {
                // 将通配符转换为正则表达式
                String regex = wildcardToRegex(trimmed);
                patterns.add(Pattern.compile(regex));
            }
        }
        
        return patterns;
    }
    
    /**
     * 将通配符模式转换为正则表达式
     * 支持 * 和 ? 通配符
     */
    private String wildcardToRegex(String wildcard) {
        StringBuilder sb = new StringBuilder();
        sb.append("^");
        
        for (int i = 0; i < wildcard.length(); i++) {
            char c = wildcard.charAt(i);
            switch (c) {
                case '*':
                    sb.append(".*");
                    break;
                case '?':
                    sb.append(".");
                    break;
                case '.':
                case '\\':
                case '+':
                case '^':
                case '$':
                case '(':
                case ')':
                case '[':
                case ']':
                case '{':
                case '}':
                case '|':
                    sb.append("\\").append(c);
                    break;
                default:
                    sb.append(c);
            }
        }
        
        sb.append("$");
        return sb.toString();
    }
    
    /**
     * 检查名称是否匹配任意一个模式
     */
    private boolean matchesAny(String name, List<Pattern> patterns) {
        for (Pattern pattern : patterns) {
            if (pattern.matcher(name).matches()) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 启动清理线程，定期清理过期的删除记录
     */
    private void startCleanupThread() {
        Thread cleanupThread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(60000);  // 每分钟清理一次
                    
                    long now = System.currentTimeMillis();
                    recentDeletes.entrySet().removeIf(
                        entry -> (now - entry.getValue()) > overwriteTimeWindow
                    );
                    
                } catch (InterruptedException e) {
                    LOG.warn("清理线程被中断", e);
                    break;
                } catch (Exception e) {
                    LOG.error("清理过期记录异常", e);
                }
            }
        });
        
        cleanupThread.setDaemon(true);
        cleanupThread.setName("AlertRuleCleanup");
        cleanupThread.start();
        
        LOG.info("启动告警规则清理线程");
    }
}

